package com.xg.frame.log.filter;

import cn.hutool.http.useragent.Browser;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.xg.frame.log.util.MyContentCachingRequestWrapper;
import com.xg.frame.log.util.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * http请求埋点
 *
 * @author dehuisun
 */
@Component
@Slf4j
public class HttpEventLogFilter extends OncePerRequestFilter {

    /**
     * 日志埋点开关，通过配置开启或关闭
     */
    @Value("${xg.log.enable}")
    private boolean enable = true;

    /**
     * 排除乱码的请求
     */
    private static final List<String> IGNORE_CONTENT_LIST = Arrays.asList("multipart/form-data", "image/gif", "image/jpeg", "image/png", "application/pdf", "application/msword", "application/octet-stream", "application/octet-stream;charset=UTF-8");

    @Value("${xg.log.exclude-url}")
    private String excludeUrls;

    private static AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        String url = request.getRequestURI();

        // 是否匹配不记录日志的路径
        boolean match = false;
        if (StringUtils.isNotBlank(excludeUrls)) {
            match = Arrays.stream(excludeUrls.split(",")).anyMatch(item -> pathMatcher.match(item, url));
        }
        // 开启日志 && 匹配不记录日志的路径
        if (!enable || match) {
            filterChain.doFilter(request, response);
            return;
        }

        // 记录日志
        log.info("请求url={}", url);
        LocalDateTime start = LocalDateTime.now();
        // 记录请求
        if (!IGNORE_CONTENT_LIST.contains(request.getContentType())) {
            // 包装请求使其可以重复读
            byte[] body = null;
            if (!(request instanceof MyContentCachingRequestWrapper)) {
                MyContentCachingRequestWrapper myContentCachingRequestWrapper = new MyContentCachingRequestWrapper(request);
                body = myContentCachingRequestWrapper.getBody();
                request = myContentCachingRequestWrapper;
            }

            //打印参数信息
            StringBuffer params = new StringBuffer();
            // 获取路径中的参数
            if (!request.getParameterMap().isEmpty()) {
                String pathParam = request.getQueryString();
                if (!StringUtils.isEmpty(pathParam)) {
                    params.append("Path参数[").append(pathParam).append("]");
                }
            }
            // 是POST或PUT请求，获取请求体中的参数
            if ("POST".equals(request.getMethod()) || "PUT".equals(request.getMethod())) {
                if (body != null && body.length > 0) {
                    params.append("Body参数[").append(new String(body, "utf-8")).append("]");
                }
            }

            String ip = RequestUtils.getRealIP(request);

            String header = request.getHeader("User-Agent");
            UserAgent ua = UserAgentUtil.parse(header);
            Browser browser = null;
            if ((!Objects.isNull(ua))) {
                browser = ua.getBrowser();
            }

            log.info("请求参数={},Method={},ip={},Browser={},Content-Type={}", params, request.getMethod(), ip, browser == null ? "" : browser.toString(), request.getContentType());
        }

        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        try {
            filterChain.doFilter(request, response);
        } catch (ServletException e) {
            log.error("TraceLogFilter", e);
        }

        List<String> list = IGNORE_CONTENT_LIST;
        String contentType = response.getContentType();
        System.out.println(list.contains(contentType));
        //记录响应
        if (!IGNORE_CONTENT_LIST.contains(response.getContentType())) {
            //响应结果,如果没有统一返回格式，此处需要改写
            String result = RequestUtils.getResponseBody(response);
            Long useTime = Duration.between(start, LocalDateTime.now()).toMillis();
            log.info("请求返回={},耗时={}ms,status={},Content-Type={}", result, useTime, response.getStatus(), response.getContentType());
        }
        //非常关键，一定要加
        updateResponse(response);
        /*int status = HttpStatus.OK.value();
        LocalDateTime start = LocalDateTime.now();
        log.info("请求url={}",request.getRequestURI());
        try {
            filterChain.doFilter(request, response);
            status = response.getStatus();
        }catch (Exception e){
            log.error("TraceLogFilter",e);
        } finally {
            if(enable&&!Objects.equals(IGNORE_CONTENT_TYPE, request.getContentType())) {
                ObjectMapper mapper = new ObjectMapper();
                LocalDateTime end = LocalDateTime.now();
                Duration duration = Duration.between(start, end);
                Long useTime = duration.toMillis();

                //请求参数
                StringBuffer requestParams = new StringBuffer();
                if("POST".equals(request.getMethod())||"PUT".equals(request.getMethod())){
                    String params = RequestUtils.getRequestBody(request);
                    requestParams.append(params);
                }else {
                    String queryString = request.getQueryString();
                    requestParams.append(queryString);
                }
                //响应结果,如果没有统一返回格式，此处需要改写
                String result = RequestUtils.getResponseBody(response);
//                R r = new R();//API统一响应封装类
//                r = mapper.readValue(result,R.class);

                String ip = RequestUtils.getRealIP(request);
                String header = request.getHeader("User-Agent");
                UserAgent ua = UserAgentUtil.parse(header);

//                EventLog eventLog = new EventLog();
//                eventLog.setParams(requestParams.toString());
//                eventLog.setUrl(request.getRequestURI());
//                eventLog.setIp(ip);
//                eventLog.setBrowser(ua == null ? "" : ua.getBrowser() == null ? "" : ua.getBrowser().toString());
//                eventLog.setOperatingSystem(ua == null ? "" : ua.getPlatform() == null ? "" : ua.getPlatform().toString());
//                eventLog.setStatus(status);
//                eventLog.setUseTime(useTime);
//                eventLog.setMsg(result);
//                eventLog.setCreateTime(start);
//                log.info(mapper.writeValueAsString(eventLog));
                log.info("请求参数={},ip={},Browser={},Content-Type={} ",requestParams,ip,ua == null ? "" : ua.getBrowser() == null ? "" : ua.getBrowser().toString(),request.getContentType());
                log.info("请求返回={},耗时={}ms,status={},Content-Type={}",result,useTime,status,response.getContentType() );

            }
            //非常关键，一定要加
            updateResponse(response);
        }*/
    }

    /**
     * 解决字节流在读取了一次之后清空的问题
     */
    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper = WebUtils
                .getNativeResponse(response, ContentCachingResponseWrapper.class);
        Objects.requireNonNull(responseWrapper).copyBodyToResponse();
    }
}
